﻿using FreeRedis;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace CoreHelper
{
    /// <summary>
    /// Redis缓存
    /// </summary>
    public class RedisCacheHelper
    {
        #region 属性与变量
        /// <summary>
        /// 缓存对象
        /// </summary>
        private static RedisClient _redisClient;
        #endregion

        #region 构造函数,必须是静态
        /// <summary>
        /// 构造函数,必须是静态
        /// </summary>
        static RedisCacheHelper()
        {
            string cacheconfig = AppSettingsManager.Get("SenparcSetting:Cache_Redis_Configuration");
            _redisClient = new FreeRedis.RedisClient(cacheconfig);
            _redisClient.Serialize = obj => JsonConvert.SerializeObject(obj);
            _redisClient.Deserialize = (json, type) => JsonConvert.DeserializeObject(json, type);
            _redisClient.Notice += (s, e) =>
            {
                if (e.Exception != null)
                    Console.WriteLine("FreeRedis日志：" + e.Log);
            };
        }
        #endregion

        #region 删除缓存
        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static long Del(params string[] key)
        {
            return _redisClient.Del(key);
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static Task<long> DelAsync(params string[] key)
        {
            return _redisClient.DelAsync(key);
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="pattern">缓存key模板匹配规则</param>
        /// <returns></returns>
        public static long DelByPattern(string pattern)
        {
            if (string.IsNullOrEmpty(pattern))
                return default;

            var keys = _redisClient.Keys(pattern);
            if (keys != null && keys.Length > 0)
            {
                return _redisClient.Del(keys);
            }

            return default;
            /*
            调用示例：
            "CaCheTest*"//删除所有以CaCheTest开头的缓存
            "*1"//删除所有以1结尾的缓存
            "[Cm]*"//删除所有第一个字符为大写C或小写m的缓存
            "[m]*[1]"//删除所有以m开头，以1结尾的缓存
            "*abc*"//删除所有包含abc的缓存,与内存缓存用法稍有差异
            更多用法请自定义正则表达式实现
            string key1 = "CaCheTest*";
            long _count = await CoreHelper.RedisCacheHelper.DelByPatternAsync(key1);
             */
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="pattern">缓存key模板匹配规则,大小写敏感</param>
        /// <returns></returns>
        public static async Task<long> DelByPatternAsync(string pattern)
        {
            if (string.IsNullOrEmpty(pattern))
                return default;

            var keys = await _redisClient.KeysAsync(pattern);
            if (keys != null && keys.Length > 0)
            {
                return await _redisClient.DelAsync(keys);
            }

            return default;
            /*
            调用示例：
            "CaCheTest*"//删除所有以CaCheTest开头的缓存
            "*1"//删除所有以1结尾的缓存
            "[Cm]*"//删除所有第一个字符为大写C或小写m的缓存
            "[m]*[1]"//删除所有以m开头，以1结尾的缓存
            "*abc*"//删除所有包含abc的缓存,与内存缓存用法稍有差异
            更多用法请自定义正则表达式实现
            string key1 = "CaCheTest*";
            long _count = await CoreHelper.RedisCacheHelper.DelByPatternAsync(key1);
             */
        }
        #endregion

        #region 检测指定键是否存在
        /// <summary>
        /// 检测指定键是否存在
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static bool Exists(string key)
        {
            return _redisClient.Exists(key);
        }

        /// <summary>
        /// 检测指定键是否存在
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static Task<bool> ExistsAsync(string key)
        {
            return _redisClient.ExistsAsync(key);
        }
        #endregion

        #region 获取缓存
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static string Get(string key)
        {
            return _redisClient.Get(key);
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static T Get<T>(string key)
        {
            return _redisClient.Get<T>(key);
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static Task<string> GetAsync(string key)
        {
            return _redisClient.GetAsync(key);
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T">获取缓存</typeparam>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static Task<T> GetAsync<T>(string key)
        {
            return _redisClient.GetAsync<T>(key);
        }
        #endregion

        #region 设置缓存
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存value</param>
        public static void Set(string key, object value)
        {
            _redisClient.Set(key, value);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存value</param>
        /// <param name="expire">过期时间</param>
        public static void Set(string key, object value, TimeSpan expire)
        {
            _redisClient.Set(key, value, expire);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存value</param>
        /// <param name="expire">过期时间</param>
        /// <returns></returns>
        public static Task SetAsync(string key, object value, TimeSpan? expire = null)
        {
            return _redisClient.SetAsync(key, value, expire.HasValue ? Convert.ToInt32(expire.Value.TotalSeconds) : 0);
        }
        #endregion

        #region 设置或获取缓存
        /// <summary>
        /// 设置或获取缓存
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="func">缓存value
        /// func示例() => fsql.Select《Models.SysConfig》().Where(a => a.sysKey == "123").ToOne()
        /// </param>
        /// <param name="expire">过期时间，例如TimeSpan.FromMinutes(60)，表示60分钟后过期</param>
        /// <returns></returns>
        public static T GetOrSet<T>(string key, Func<T> func, TimeSpan? expire = null)
        {
            #region 判断缓存key是否存在,存在执行此处代码
            if (_redisClient.Exists(key))
            {
                try
                {
                    //存在，根据key获取缓存数据并返回
                    return _redisClient.Get<T>(key);
                }
                catch
                {
                    //异常，删除指定key的缓存值
                    _redisClient.Del(key);
                }
            }
            #endregion
            //缓存key不存在，直接返回func的值
            var result = func.Invoke();
            //设置缓存
            _redisClient.Set(key, result, expire.HasValue ? Convert.ToInt32(expire.Value.TotalSeconds) : 0);

            return result;

            /*
            调用示例：
            string key1 = "CaCheTest:T_GetOrSetTest1";
            string string1 = CoreHelper.RedisCacheHelper.GetOrSet<string>(key1, () => BLL.IFsql.fsql.Select<Models.users>().Where(a => a.Id == 1).ToOne(a => a.name), TimeSpan.FromMinutes(3));

            string key2 = "CaCheTest:T_GetOrSetTest2";
            Models.users _models_users = CoreHelper.RedisCacheHelper.GetOrSet<Models.users>(key2, () => BLL.IFsql.fsql.Select<Models.users>().Where(a => a.Id == 1).ToOne(), TimeSpan.FromMinutes(3));
             */
        }

        /// <summary>
        /// 设置或获取缓存
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="func">缓存value
        /// func示例() => fsql.Select《Models.SysConfig》().Where(a => a.sysKey == "123").ToOne()
        /// </param>
        /// <param name="expire">过期时间，例如TimeSpan.FromMinutes(60)，表示60分钟后过期</param>
        /// <returns></returns>
        public static async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> func, TimeSpan? expire = null)
        {
            #region 判断缓存key是否存在,存在执行此处代码
            if (await _redisClient.ExistsAsync(key))
            {
                try
                {
                    //存在，根据key获取缓存数据并返回
                    return await _redisClient.GetAsync<T>(key);
                }
                catch
                {
                    //异常，删除指定key的缓存值
                    await _redisClient.DelAsync(key);
                }
            }
            #endregion
            //缓存key不存在，直接返回func的值
            var result = await func.Invoke();
            //设置缓存
            await _redisClient.SetAsync(key, result, expire.HasValue ? Convert.ToInt32(expire.Value.TotalSeconds) : 0);

            return result;

            /*
            调用示例：
            string key1 = "CaCheTest:T_GetOrSetAsyncTest1";
            string string1 = await CoreHelper.RedisCacheHelper.GetOrSetAsync<string>(key1, () => BLL.IFsql.fsql.Select<Models.users>().Where(a => a.Id == 1).ToOneAsync(a => a.name), TimeSpan.FromMinutes(3));

            string key2 = "CaCheTest:T_GetOrSetAsyncTest2";
            Models.users _models_users = await CoreHelper.RedisCacheHelper.GetOrSetAsync<Models.users>(key2, () => BLL.IFsql.fsql.Select<Models.users>().Where(a => a.Id == 1).ToOneAsync(), TimeSpan.FromMinutes(3));
             */
        }
        #endregion

        #region 获取缓存集合
        /// <summary>
        /// 获取所有缓存键
        /// </summary>
        /// <returns></returns>
        public static List<string> GetCacheKeys()
        {
            // 获取数据库实例  
            var db = _redisClient.GetDatabase();

            // 获取所有键的集合，并转换为数组  
            string[] _RedisKeys = db.Keys("*");

            List<string> keys = new List<string>();
            foreach (var item in _RedisKeys)
            {
                keys.Add(item.ToString());
            }
            return keys;
        }

        /// <summary>
        /// 获取缓存集合
        /// </summary>
        /// <returns></returns>
        public static IDictionary<string, object> GetAll()
        {
            // 获取数据库实例  
            var db = _redisClient.GetDatabase();
            // 获取所有键的集合，并转换为数组  
            string[] _RedisKeys = db.Keys("");
            var dict = new Dictionary<string, object>();
            foreach (var item in _RedisKeys)
            {
                dict.Add(item, db.Get(item));
            }
            return dict;
        }
        #endregion
    }
}